﻿using Coldairarrow.Business.Base_Manage;
using Coldairarrow.Entity.BackStage.ConsumeChats;
using Coldairarrow.Entity.BackStage.Platform;
using Coldairarrow.Entity.Base_Manage;
using Coldairarrow.Entity.BTB_StaffUsers;
using Coldairarrow.IBusiness;
using Coldairarrow.Util;
using Coldairarrow.Util.DTO.OnlineChat;
using EFCore.Sharding;
using LinqKit;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace Coldairarrow.Business.BackStage.ConsumeChats
{
    public class ConsumeServerBusiness : BaseBusiness<ConsumeServer>, IConsumeServerBusiness, ITransientDependency
    {
        readonly IOperator _operator;
        readonly IServiceProvider _serviceProvider;
        private readonly IHubContext<MessageHub> _messageHub;
        readonly string userDefaultHeadImg = "http://qnmzptapi.xazkrj.cn/Upload/HeadPort/dhead.jpg";
        readonly string KfDefaultHeadImg = "/HeadImg/kefu002.png";

        public ConsumeServerBusiness(IDbAccessor repository,IOperator @operator, IHubContext<MessageHub> messageHub, IServiceProvider serviceProvider)
            : base(repository)
        {
            _operator = @operator;
            _serviceProvider = serviceProvider;
            _messageHub = messageHub;
        }

        #region 外部接口

        public async Task<PageResult<Base_UserDTO>> GetUserDataListAsync(PageInput<GetUsersInputDTO> input)
        {
            var suids = GetIQueryable().Where(s => s.State == true).Select(x => x.UserId).Distinct().ToList();

            Expression<Func<Base_User, Base_Department, ConsumeServer, Base_Platform, Base_UserDTO>> select = (a, b, c,d) => new Base_UserDTO
            {
                IsCService = suids.Contains(a.Id)?true:false,
                CServiceClass = c.ClassId,
                DepartmentName = b.Name,
                HeadImg = c.HeadImg,
                PlantName = d.Name
            };
            var search = input.Search;
            select = select.BuildExtendSelectExpre();
            var q_User = Service.GetIQueryable<Base_User>();
            var q = from a in q_User.AsExpandable()
                    join b in Service.GetIQueryable<Base_Department>() on a.DepartmentId equals b.Id into ab
                    from b in ab.DefaultIfEmpty()
                    join c in Service.GetIQueryable<ConsumeServer>() on a.Id equals c.UserId into ac
                    from c in ac.DefaultIfEmpty()
                    join d in Service.GetIQueryable<Base_Platform>() on c.ClassId equals d.Sort into cd
                    from d in cd.DefaultIfEmpty()
                    select @select.Invoke(a, b, c, d);

            var where = LinqHelper.True<Base_UserDTO>();

            if (!search.userId.IsNullOrEmpty())
            {
                where = where.And(x => x.Id == search.userId);
            }

            if (search.ClassId.HasValue)
            {
                where = where.And(x => x.CServiceClass == search.ClassId.Value);
            }

            if (search.IsCService.HasValue)
            {
                where = where.And(x => x.IsCService == search.IsCService.Value);
            }
            if (!search.keyword.IsNullOrEmpty())
            {
                var keyword = $"%{search.keyword}%";
                q = q.Where(x =>
                      EF.Functions.Like(x.UserName, keyword)
                      || EF.Functions.Like(x.RealName, keyword));
            }

            var list = await q.Where(where).GetPageResultAsync(input);

            await SetProperty(list.Data);

            return list;

            async Task SetProperty(List<Base_UserDTO> users)
            {
                //补充用户角色属性
                List<string> userIds = users.Select(x => x.Id).ToList();
                var userRoles = await (from a in Service.GetIQueryable<Base_UserRole>()
                                       join b in Service.GetIQueryable<Base_Role>() on a.RoleId equals b.Id
                                       where userIds.Contains(a.UserId)
                                       select new
                                       {
                                           a.UserId,
                                           RoleId = b.Id,
                                           b.RoleName
                                       }).ToListAsync();
                users.ForEach(aUser =>
                {
                    var roleList = userRoles.Where(x => x.UserId == aUser.Id);
                    aUser.RoleIdList = roleList.Select(x => x.RoleId).ToList();
                    aUser.RoleNameList = roleList.Select(x => x.RoleName).ToList();
                });
            }
        }

        public async Task<PageResult<ConsumeServer>> GetDataListAsync(PageInput<ConditionDTO> input)
        {
            var q = GetIQueryable();
            var where = LinqHelper.True<ConsumeServer>();
            var search = input.Search;

            //筛选
            if (!search.Condition.IsNullOrEmpty() && !search.Keyword.IsNullOrEmpty())
            {
                var newWhere = DynamicExpressionParser.ParseLambda<ConsumeServer, bool>(
                    ParsingConfig.Default, false, $@"{search.Condition}.Contains(@0)", search.Keyword);
                where = where.And(newWhere);
            }

            return await q.Where(where).GetPageResultAsync(input);
        }

        public async Task<ConsumeServer> GetTheDataAsync(string id)
        {
            return await GetEntityAsync(id);
        }

        /// <summary>
        /// 将用户设置为客服
        /// </summary>
        /// <param name="id">用户Id</param>
        /// <returns></returns>
        /// <exception cref="BusException"></exception>
        public async Task SetUserToCustomrtServer(string id, int ClassId)
        {

            var aCount = GetIQueryable().Where(x => x.UserId.Equals(id) && x.State == true).Count();
            if (aCount > 0)
            {
                throw new BusException("该用户已设置为客服，无法重复设置！");
            }
            else
            {
                var user = Service.GetIQueryable<Base_User>().Where(x => x.Id.Equals(id)).FirstOrDefault();
                if (user.IsNullOrEmpty())
                {
                    throw new BusException("查询该用户信息为空，设置客服失败！");
                }
                else 
                {
                    ConsumeServer model = new ConsumeServer();
                    var aModel = await GetIQueryable().Where(x => x.UserId.Equals(id) && x.State == false).FirstOrDefaultAsync();
                    if (aModel.IsNullOrEmpty())
                    {
                        ConsumeServer cmodel = new ConsumeServer();
                        cmodel.Id = IdHelper.GetId();
                        cmodel.CreateTime = DateTime.Now;
                        cmodel.CreatorId = _operator.UserId;
                        cmodel.Deleted = false;
                        cmodel.ClassId = ClassId;
                        cmodel.UserId = id;
                        cmodel.HeadImg = "/HeadImg/kefu001.jpg";
                        cmodel.ServiceNo = GetTheNo().ToString();
                        cmodel.State = true;
                        await InsertAsync(cmodel);

                        model = cmodel;
                    }
                    else
                    {
                        aModel.State = true;
                        aModel.ClassId = ClassId;
                        await UpdateAsync(aModel);

                        model = aModel;
                    }
                   

                    var cache = _serviceProvider.GetService<IDistributedCache>();
                    List<CServiceDTO> cList = new List<CServiceDTO>();
                    var cstr = cache.GetString("OCSUserList");
                    if (!cstr.IsNullOrEmpty() && !cstr.Contains("{"))
                    {
                        cstr ="";
                        cache.SetString("OLinkUserList", cstr);
                    }
                    if (!cstr.IsNullOrEmpty())
                    {
                        cList = JsonConvert.DeserializeObject<List<CServiceDTO>>(cstr);
                        var slist = cList.Where(m => m.Id.Equals(model.UserId)).ToList();
                        if (slist.Count == 0)
                        {
                            //创建新关系
                            CServiceDTO cmodel = new CServiceDTO();
                            cmodel.Id = model.UserId;
                            cmodel.ClassId = model.ClassId;
                            cmodel.OnChatRoomId = "";
                            cList.Add(cmodel);
                            cache.SetString("OCSUserList", cList.ToJson().ToString());
                        }
                        else 
                        {
                            //删除原关系
                            foreach (var item in slist)
                            {
                                var index = cList.IndexOf(item);
                                cList.RemoveAt(index);
                            }

                            //创建新关系
                            CServiceDTO cmodel = new CServiceDTO();
                            cmodel.Id = model.UserId;
                            cmodel.ClassId = model.ClassId;
                            cmodel.OnChatRoomId = "";
                            cList.Add(cmodel);
                            cache.SetString("OCSUserList", cList.ToJson().ToString());
                        }

                    }
                    else
                    {
                        cList = new List<CServiceDTO>();
                        CServiceDTO cmodel = new CServiceDTO();
                        cmodel.Id = model.UserId;
                        cmodel.ClassId = model.ClassId;
                        cmodel.OnChatRoomId = "";
                        cList.Add(cmodel);
                        cache.SetString("OCSUserList", cList.ToJson().ToString());
                    }

                    //刷新客服未读消息数量
                    await SendCSUnReadNum(id, ClassId);

                    //刷新客服用户列表
                    await UpdateCSRoomList(id, ClassId);
                }
            }


        }

        /// <summary>
        /// 取消用户的客服状态
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task DeleteUserToCustomrtServer(string id)
        {
            var user = Service.GetIQueryable<Base_User>().Where(x => x.Id.Equals(id)).FirstOrDefault();
            if (user.IsNullOrEmpty())
            {
                throw new BusException("查询该用户信息为空，取消客服失败！");
            }
            else
            {
                var ids = await GetIQueryable().Where(x => x.UserId.Equals(id)).Select(m => m.Id).Distinct().ToListAsync();
                if (ids.Count > 0)
                {
                    await UpdateAsync(s => ids.Contains(s.Id), m => { m.ClassId = -1; m.State = false; });

                    var cache = _serviceProvider.GetService<IDistributedCache>();
                    List<CServiceDTO> cList = new List<CServiceDTO>();
                    var cstr = cache.GetString("OCSUserList");
                    if (!cstr.Contains("{"))
                    {
                        cstr = "";
                        cache.SetString("OCSUserList", cstr);
                    }
                    if (!cstr.IsNullOrEmpty())
                    {
                       
                        cList = JsonConvert.DeserializeObject<List<CServiceDTO>>(cstr);
                        var sList = cList.Where(m => ids.Contains(m.Id));
                        if (sList.Count() > 0)
                        {
                            //删除原关系
                            foreach (var item in sList)
                            {
                                var index = cList.IndexOf(item);
                                cList.RemoveAt(index);
                            }

                            cache.SetString("OCSUserList", cList.ToJson().ToString());
                        }

                    }

                    //在线客服列表移除
                    var jstr = cache.GetString("OLinkUserList");
                    if (!jstr.IsNullOrEmpty())
                    {
                        if (!jstr.Contains("{"))
                        {
                            jstr ="";
                            cache.SetString("OLinkUserList", jstr);
                        }
                        else
                        {
                            var uList = JsonConvert.DeserializeObject<List<OnLinkUserDTO>>(jstr);
                            var bModel = uList.Where(x => x.UserId.Equals(id) && x.GroupName.Equals("CS" + id)).FirstOrDefault();
                            if (!bModel.IsNullOrEmpty())
                            {

                                var index = uList.IndexOf(bModel);
                                cList.RemoveAt(index);


                                //新用户缓存
                                cache.SetString("OLinkUserList", uList.ToJson().ToString());
                            }
                        }
                    }


                    #region//将房间客服设置为结束状态
                    //获取客服用户Id
                    var rsIds = Service.GetIQueryable<ChatRoomCSUser>().Where(s => s.ConstmeServerId.Equals(id) && s.State == true).Select(s => s.Id).ToList();
                    if (rsIds.Count > 0)
                    {
                        await Service.UpdateAsync<ChatRoomCSUser>(s => rsIds.Contains(s.Id), m => { m.EndTime = DateTime.Now; m.State = false; });
                    }
                    #endregion

                    //刷新客服未读消息数量
                    await SendCSUnReadNum(id, -1);

                    //刷新客服用户列表
                    await UpdateCSRoomList(id, -1);
                }
            }
        }

        /// <summary>
        /// 后台——客服修改自己头像和昵称
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task SetServerInfoAsync(SetServerInfoDTO input)
        {
            if (input.UserId.IsNullOrEmpty())
            {
                input.UserId = _operator.UserId;
            }

            if (input.UserId.ToLower() == "admin" && !input.NickName.Equals("超级管理员"))
            {
                throw new BusException("超级管理员昵称信息无法修改！");
            }

            var user = Service.GetIQueryable<Base_User>().Where(x => x.Id.Equals(input.UserId)).FirstOrDefault();
            if (user.IsNullOrEmpty())
            {
                throw new BusException("查询该用户信息为空，取消客服失败！");
            }
            else 
            {
                var suser = GetIQueryable().Where(x => x.UserId.Equals(input.UserId)).FirstOrDefault();
                if (suser.IsNullOrEmpty())
                {
                    throw new BusException("该用户不是客服设置客服头像失败！");
                }

                if (!input.NickName.IsNullOrEmpty())
                {
                    user.RealName = input.NickName;
                    await Service.UpdateAsync(user);
                }


                if (!input.HeadImg.IsNullOrEmpty())
                {
                    suser.HeadImg = input.HeadImg;
                    await UpdateAsync(suser);
                }
                
            }
        }

        /// <summary>
        /// 后台——客服获取自己名称和头像
        /// </summary>
        /// <returns></returns>
        public async Task<SetServerInfoDTO> GetCServerInfoAsync()
        {
            SetServerInfoDTO res = new SetServerInfoDTO();
            res.ClassId = -1;
            var model = Service.GetIQueryable<Base_User>().Where(x => x.Id.Equals(_operator.UserId)).FirstOrDefault();
            if (!model.IsNullOrEmpty())
            {
                var uModel = await GetIQueryable().Where(s => s.UserId.Equals(model.Id)).FirstOrDefaultAsync();
                if (!uModel.IsNullOrEmpty())
                {
                    res.UserId = model.Id;
                    res.ClassId = uModel.State ? uModel.ClassId : -1;
                    res.NickName = model.RealName;
                    res.HeadImg = uModel.HeadImg;
                }
                else
                {
                    res.UserId = model.Id;
                    res.NickName = model.RealName;
                }

            }

            return res;
        }

        #endregion

        #region 私有成员
        /// <summary>
        /// 刷新客服未读消息数量
        /// </summary>
        private async Task SendCSUnReadNum(string CSUserId, int ClassId)
        {
            //判断用户是否客服
            var aCount = Service.GetIQueryable<ConsumeServer>().Where(s => s.UserId.Equals(CSUserId) && ClassId > -1 && s.State == true).Count();
            if (aCount > 0)
            {
                //获取房间未读消息
                int uReadCount = (from a in Service.GetIQueryable<ChatContent>().Where(m => m.ReceiverId.Equals(CSUserId) && m.ReadState == false)
                                  join b in Service.GetIQueryable<ChatRoom>().Where(m => m.ClassId.Equals(ClassId)) on a.RoomId equals b.Id
                                  select a).Count();

                Log.Information("SendCSUnReadNum=>uReadCount:{0}", uReadCount);
                await _messageHub.Clients.Groups("CS" + CSUserId).SendAsync("UserUnread", uReadCount);
            }
            else
            {
                await _messageHub.Clients.Groups("CS" + CSUserId).SendAsync("UserUnread", -1);
            }
        }


        /// <summary>
        /// 刷新客服房间列表
        /// </summary>
        /// <param name="CSUserId"></param>
        /// <param name="ClassId"></param>
        /// <returns></returns>
        private async Task UpdateCSRoomList(string CSUserId, int ClassId)
        {

            var list = await (from a in Service.GetIQueryable<ConsumeServer>().Where(h => h.ClassId == ClassId && h.UserId.Equals(CSUserId))
                              join k in Service.GetIQueryable<ChatRoomCSUser>().Where(m => m.State == true) on a.UserId equals k.ConstmeServerId
                              join b in Service.GetIQueryable<ChatRoom>().Where(x => x.ClassId == ClassId) on k.RoomId equals b.Id
                              join c in Service.GetIQueryable<BTB_StaffUser>() on b.UserId equals c.id into bc
                              from c in bc.DefaultIfEmpty()
                              select new
                              {
                                  RId = b.Id,
                                  RName = b.ChatRoot_Name,
                                  UId = b.UserId,
                                  UHeadImg = c.HeadPortrait,
                                  UheadType = c.HeadType,
                                  UName = c.NickName
                              }).ToListAsync();

            List<SRoomDTO> dList = new List<SRoomDTO>();
            foreach (var item in list)
            {
                SRoomDTO rModel = new SRoomDTO();
                rModel.RoomId = item.RId;
                if (item.UName.IsNullOrEmpty())
                {
                    rModel.UserId = "USE" + item.UId;
                    rModel.RoomName = "游客"+item.UId.Substring(item.UId.Length - 5);
                    rModel.HeadType = 1;
                    rModel.HeadImg = userDefaultHeadImg;
                }
                else
                {
                    rModel.UserId = "USE" + item.UId;
                    rModel.RoomName = item.UName;
                    rModel.HeadImg = item.UHeadImg.IsNullOrEmpty() ? userDefaultHeadImg : item.UHeadImg;
                    rModel.HeadType =item.UHeadImg.IsNullOrEmpty() ? 1 : item.UheadType;

                }

                //获取房间最新消息
                var message = await Service.GetIQueryable<ChatContent>().Where(x => x.RoomId.Equals(item.RId)).OrderByDescending(m => m.CreateTime).FirstOrDefaultAsync();
                if (!message.IsNullOrEmpty())
                {
                    rModel.MSTime = message.CreateTime;
                    rModel.messageType = message.MessageType;
                    rModel.NewMassage = message.MessageContent;
                    if (rModel.messageType == 12 || rModel.messageType == 11)
                    {
                        rModel.NewMassage ="[自动回复]";
                    }
                }

                //获取房间客服未读消息数量
                rModel.MSCount =  Service.GetIQueryable<ChatContent>().Where(x => x.RoomId.Equals(item.RId) && x.ReadState == false && x.ReceiverId.Equals(CSUserId)).Count();
                dList.Add(rModel);
            }

            dList = dList.OrderByDescending(x => x.MSTime).ToList();
            Log.Information("SendCSUnReadNum=>dList:{0}", dList.Count);
            await _messageHub.Clients.Groups("CS" + CSUserId).SendAsync("StaffRoomList", dList);
        }

        private int GetTheNo()
        {
            Random Rdm = new Random();
            //产生0到100的随机数
            int iRdm = Rdm.Next(100000, 999999);

            var sCount = GetIQueryable().Where(x => x.ServiceNo.Equals(iRdm.ToString())).Count();
            if (sCount > 0)
            {
                GetTheNo();
            }

            return iRdm;
        }

        public async Task<SetServerInfoDTO> GetTheUserDataAsync(IdInputDTO idInput)
        {
            SetServerInfoDTO res = new SetServerInfoDTO();
            if (idInput.Id.IsNullOrEmpty())
            {
                throw new Exception("用户id不能为空!!!");
            }
            var usermodel = await Db.GetIQueryable<Base_User>().Where(x => x.Id.Equals(idInput.Id)).FirstOrDefaultAsync();
            var headmodel = await Db.GetIQueryable<ConsumeServer>().Where(x => x.UserId.Equals(idInput.Id)).FirstOrDefaultAsync();
            if (!usermodel.IsNullOrEmpty())
            {
                res.UserId = idInput.Id;
                res.NickName = usermodel.RealName;
            }
            if (!headmodel.IsNullOrEmpty())
            {
                res.HeadImg = headmodel.HeadImg;
                res.ClassId = headmodel.ClassId;
            }

            return res;
        }
        #endregion
    }
}